﻿#include "MainFrame.h"
#include "wx/log.h"
#include "wx/graphics.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

MainFrame::MainFrame(wxWindow* parent)
:
MainFrame_base(parent)
{
	// Redirect log messages
	wxLog::SetActiveTarget(new wxLogTextCtrl(m_log));
	wxLogMessage("Log initialized");

	// Set AUI flags
	m_mgr.SetFlags(wxAUI_MGR_ALLOW_ACTIVE_PANE | wxAUI_MGR_TRANSPARENT_DRAG | wxAUI_MGR_ALLOW_FLOATING |
				   wxAUI_MGR_TRANSPARENT_HINT | wxAUI_MGR_HINT_FADE |
				   wxAUI_MGR_NO_VENETIAN_BLINDS_FADE);

	m_mgr.Update();

	this->Bind(wxEVT_THREAD_UPDATE, &MainFrame::OnThreadUpdate, this);
}

void MainFrame::OnCameraControls(wxCommandEvent& event)
{
	int id = event.GetId();

	switch (id)
	{
	case ID_MENU_START_CAMERA:
	case ID_TB_START_CAMERA:
	{
		if (CreateThread(wxTHREAD_DETACHED) != wxTHREAD_NO_ERROR)
		{
			wxLogMessage("Error: Could not create the worker thread!");
			return;
		}

		if (GetThread()->Run() != wxTHREAD_NO_ERROR)
		{
			wxLogMessage("Error: Could not run the worker thread!");
			return;
		}
		break;
	}
	case ID_MENU_PAUSE_RESUME:
	case ID_TB_PAUSE_RESUME:
	{
		if (!this->GetThread()) return;
		if (!this->GetThread()->IsPaused())
		{
			this->GetThread()->Pause();
			wxLogMessage("Camera paused");
		} else
		{
			this->GetThread()->Resume();
			wxLogMessage("Camera running");
		}
		break;
	}
	default: break;
	}
}

void MainFrame::OnMenuExit(wxCommandEvent& event)
{
	this->Close();
}

void MainFrame::OnClose(wxCloseEvent& event)
{
	if (!this->GetThread())
	{
		this->Destroy();
		return;
	}

	if (this->GetThread()->Delete() != wxTHREAD_NO_ERROR)
		wxLogMessage("Error: Can't delete the camera thread!");

	while (true)
	{
		if (!this->GetThread()) break;
		this->GetThread()->Sleep(15);
	}

	this->Destroy();
	event.Skip();
}

void MainFrame::OnUpdateUI(wxUpdateUIEvent& event)
{
	event.Skip();
}

void MainFrame::OnIdle(wxIdleEvent& event)
{
	event.Skip();
}

wxThread::ExitCode MainFrame::Entry()
{
	wxLogMessage("Initializing camera...");

	// Initialize the OpenCV capture device. This has to be done in the secondary thread context!
	cv::VideoCapture capture_device(0);
	if (!capture_device.isOpened())
	{
		wxLogMessage("Error: Couldn't initialize camera!");
		return (wxThread::ExitCode)0;
	}

	cv::Mat captured_image;

	while (!this->GetThread()->TestDestroy())
	{
		capture_device >> captured_image;
		if (captured_image.empty()) return static_cast<wxThread::ExitCode>(0);

		cv::cvtColor(captured_image, captured_image, CV_BGR2RGB);

		{
			wxCriticalSectionLocker lock(m_cs_image);
			m_video_image = wxImage(captured_image.cols, captured_image.rows, captured_image.data, true);
		}

		wxQueueEvent(this, new wxThreadEvent(wxEVT_THREAD_UPDATE));

		this->GetThread()->Sleep(10);
	}

	return static_cast<wxThread::ExitCode>(0);
}

void MainFrame::OnThreadUpdate(wxThreadEvent& event)
{
	wxClientDC dc(m_camera_panel);
	this->Render(dc);
}

void MainFrame::OnCameraPanelPaint(wxPaintEvent& event)
{
	wxPaintDC dc(m_camera_panel);
	this->Render(dc);
}

void MainFrame::OnCameraPanelSize(wxSizeEvent& event)
{
	m_camera_panel->Refresh();
}

void MainFrame::Render(wxDC &dc)
{
	if (!dc.IsOk() || !m_video_image.IsOk()) return;

	int win_width	= m_camera_panel->GetClientSize().GetX();
	int win_height	= m_camera_panel->GetClientSize().GetY();

	wxCriticalSectionLocker lock(m_cs_image);

	int img_width	= m_video_image.GetSize().GetX();
	int img_height	= m_video_image.GetSize().GetY();

	int new_img_width	= (img_width	*	win_height)		/	img_height;
	int new_img_height	= (img_height	*	win_width)		/	img_width;
	int width_diff		= (win_width	-	new_img_width)	/	2;
	int height_diff		= (win_height	-	new_img_height)	/	2;

	if (height_diff >= 0)
	{
		dc.DrawBitmap(wxBitmap(m_video_image.Scale(win_width, new_img_height)), 0, height_diff);
	} else
	{
		dc.DrawBitmap(wxBitmap(m_video_image.Scale(new_img_width, win_height)), width_diff, 0);
	}
}
